package com.fred.colorpicker
import androidx.compose.foundation.gestures.detectDragGestures
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.layout.MeasurePolicy
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.layout.positionInParent
import androidx.compose.ui.layout.positionInRoot
import androidx.compose.ui.layout.positionInWindow
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import kotlin.math.max

@Composable
fun ColorPicker(modifier: Modifier = Modifier,
                colorChanged: ((rectColor: Int?, ringColor: Int?) -> Unit)? = null) {
    Column(modifier = modifier) {
        val processor = GraySeekBarProcessor(LocalContext.current,colorChanged)
        val rectChanged = { color:Int, hsv:FloatArray ->
            processor.setSelect(isRect = true, isRing = false, color = color, hsv)
        }
        val ringChanged = {color:Int, hsv:FloatArray ->
            processor.setSelect(isRect = false, isRing = true,color = color, hsv)
        }

        ColorWheelPalette(modifier = Modifier, rectChanged, ringChanged)
        GraySeekBar(modifier = Modifier.padding(0.dp,8.dp),
                    processor)
    }

}

@Composable
private fun ColorWheelPalette(modifier: Modifier = Modifier,
                              rectChanged: ((selectColor: Int, selectHsv: FloatArray) -> Unit)? = null,
                              ringChanged: ((selectColor: Int, selectHsv: FloatArray) -> Unit)? = null) {

    val palette = Palette(LocalContext.current, rectChanged, ringChanged)
    val measurePolicy = MeasurePolicy { _, constraints ->
        layout (constraints.maxWidth, constraints.maxWidth) {}
    }
    val slideModifier = Modifier.pointerInput("slide") {
        detectDragGestures(onDragStart = {
            palette.dragStart(it)
        }, onDragEnd = {
            palette.dragEnd()
        }, onDragCancel = {
            palette.dragEnd()
        }, onDrag = { change, dragAmount ->
            palette.drag(change.position, dragAmount)
        })
    }
    val tapModifier = Modifier.pointerInput("tap") {
        detectTapGestures(onTap = {
            palette.dragEnd()
        },
        onPress = { offset ->
            palette.onPress(offset)
        })
    }
    Layout(
        content = {},
        modifier = modifier
            .drawWithContent {
                drawIntoCanvas { canvas ->
                    palette.paint(canvas)
                }
            }
            .onGloballyPositioned { layoutCoordinates ->
               palette.updateState(layoutCoordinates.size)
            }
            .then(slideModifier)
            .then(tapModifier)
            .then(modifier),
        measurePolicy = measurePolicy
    )
}

@Composable
fun GraySeekBar(modifier: Modifier = Modifier,
                processor: GraySeekBarProcessor) {
    val minHeight = LocalContext.current.dip(30F).toInt()
    val measurePolicy = MeasurePolicy { _, constraints ->
        layout (constraints.maxWidth, max(minHeight, constraints.minHeight)) {}
    }

    val slideModifier = Modifier.pointerInput("slide") {
        detectDragGestures(onDragStart = {
            processor.dragStart(it)
        }, onDragEnd = {
            processor.dragEnd()
        }, onDragCancel = {
            processor.dragEnd()
        }, onDrag = { change, dragAmount ->
            processor.drag(change.position, dragAmount)
        })
    }
    val tapModifier = Modifier.pointerInput("tap") {
        detectTapGestures(onTap = {
            processor.dragEnd()
        },
      onPress = { offset ->
          processor.onPress(offset)
      })
    }
    Layout(
        content = {},
        modifier = modifier
            .drawWithContent {
                drawIntoCanvas { canvas ->
                    processor.paint(canvas)
                }
            }
            .onGloballyPositioned { layoutCoordinates ->
                processor.updateState(layoutCoordinates.size)
            }
            .then(slideModifier)
            .then(tapModifier)
            .then(modifier),
        measurePolicy = measurePolicy
    )
}